<template>
  <!-- <Spin :tip="loadingText" :spinning="loading"> -->
  <section ref="sceneContainerRef" class="w-full h-full"></section>
  <!--  </Spin> -->
</template>

<script lang="ts" setup>
  import { onBeforeUnmount, onMounted, ref } from 'vue';
  import * as THREE from 'three';
  import useWindowResize from './hooks/use-window-resize';
  import {
    getScene,
    getRenderer,
    getAmbientLight,
    getStats,
    getOrbitControls,
    getTextareaLoader,
    getDirectionalLight,
    getFog,
    getBokehPass,
    disposeGltfLoader,
  } from './three-utils';
  import skyBg from './assets/imgs/sky.png';
  import useCamera from './hooks/use-camera';
  import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
  import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
  import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';
  import { SMAAPass } from 'three/addons/postprocessing/SMAAPass.js';
  // import useRaycaster from './hooks/use-raycaster';
  // import { loadModel } from './load-model/index';

  /**
   * 场景宽度
   */
  let sceneWidth = window.innerWidth;
  /**
   * 场景高度
   */
  let sceneHeight = window.innerHeight;
  /**
   * 摄像机
   */
  const { getFlyCamera, getOrbitControlsCamera } = useCamera({
    // 切换成 flyCamera 时 不让场景旋转
    onCameraChange: (isUseFlyCamera) => {
      orbitControls.enabled = !isUseFlyCamera;
    },
  });
  /**
   * scene容器
   */
  const sceneContainerRef = ref<HTMLElement | null>(null);
  /**
   * 场景
   */
  const scene = getScene();
  /**
   * 摄像机
   */
  const orbitControlsCamera = getOrbitControlsCamera();
  /**
   * 飞翔摄像机
   */
  const flyCamera = getFlyCamera();
  /**
   * 渲染器
   */
  const renderer = getRenderer(sceneWidth, sceneHeight);
  /**
   * 环境光
   */
  const ambientLight = getAmbientLight();
  /**
   * 雾
   */
  const fog = getFog();
  scene.fog = fog;
  /**
   * 平行光
   */
  const directionalLight = getDirectionalLight();
  /**
   * 帧率指示器
   */
  const stats = getStats();
  // /**
  //  * 射线检测
  //  */
  // const { handleMouseDown } = useRaycaster({
  //   getScene: () => scene,
  //   getOrbitControlsCamera: () => orbitControlsCamera,
  // });
  /**
   * 控制器
   */
  const orbitControls = getOrbitControls(orbitControlsCamera, renderer.domElement);
  /**
   * 材质加载器
   */
  const textareaLoader = getTextareaLoader();
  /**
   * 加载天空贴图
   */
  const skyMap = textareaLoader.load(skyBg);
  skyMap.mapping = THREE.EquirectangularReflectionMapping;
  scene.background = skyMap;
  /**
   * 景深效果
   */
  const bokehPass = getBokehPass(scene, orbitControlsCamera);
  /**
   * 输出通道
   */
  const outputPass = new OutputPass();
  /**
   * 抗锯齿
   */
  const smaaPass = new SMAAPass(sceneWidth, sceneHeight);
  /**
   * 场景渲染
   */
  const renderScene = new RenderPass(scene, orbitControlsCamera);
  /**
   * 后期效果
   */
  const composer = new EffectComposer(renderer);
  // 模版缓冲（stencil buffer） https://blog.csdn.net/silangquan/article/details/46608915
  composer.renderTarget1.stencilBuffer = true;
  composer.renderTarget2.stencilBuffer = true;
  composer.setSize(sceneWidth, sceneHeight);
  composer.addPass(renderScene);
  composer.addPass(bokehPass);
  composer.addPass(smaaPass);
  composer.addPass(outputPass);

  /**
   * 初始化场景
   */
  const init = () => {
    sceneContainerRef.value!.appendChild(stats.dom);
    sceneContainerRef.value!.appendChild(renderer!.domElement);
    renderer.setAnimationLoop(animate);
  };

  /**
   * 当页面尺寸发生变化时
   */
  const onWindowResize = () => {
    sceneWidth = window.innerWidth;
    sceneHeight = window.innerHeight;
    orbitControlsCamera.aspect = sceneWidth / sceneHeight;
    flyCamera.aspect = sceneWidth / sceneHeight;
    orbitControlsCamera.updateProjectionMatrix();
    flyCamera.updateProjectionMatrix();
    renderer!.setSize(sceneWidth, sceneHeight);
    composer.setSize(sceneWidth, sceneHeight);
  };

  /**
   * 刷新动画状态
   */
  const animate = () => {
    stats.update();
    orbitControls.update();
    // renderer!.render(scene, orbitControlsCamera);
    renderer.clear();
    composer.render(0.2);
  };

  /**
   * 当浏览器窗口尺寸变化
   */
  useWindowResize(onWindowResize);

  /**
   * 渲染灯光和相机
   */
  scene.add(ambientLight, orbitControlsCamera, flyCamera, directionalLight);
  // loadModel({ scene, skyMap });
  onMounted(() => {
    init();
  });

  onBeforeUnmount(() => {
    const gl = renderer.domElement.getContext('webgl');
    gl && gl.getExtension('WEBGL_lose_context')?.loseContext();
    renderer.forceContextLoss();
    skyMap.dispose();
    disposeGltfLoader();

    // 清理场景中的对象
    if (scene) {
      scene.traverse((child) => {
        if (child instanceof THREE.Mesh) {
          child.geometry.dispose();
          if (child.material instanceof THREE.Material) {
            child.material.dispose();
          } else if (Array.isArray(child.material)) {
            child.material.forEach((mat) => mat.dispose());
          }
        }
      });

      // 移除光源
      if (ambientLight) {
        scene.remove(ambientLight);
        ambientLight.dispose();
      }

      if (directionalLight) {
        scene.remove(directionalLight);
        directionalLight.dispose;
      }

      // 移除摄像机
      if (orbitControlsCamera) {
        scene.remove(orbitControlsCamera);
      }

      if (flyCamera) {
        scene.remove(flyCamera);
      }

      // 移除帧率指示器
      if (stats && stats.dom.parentNode) {
        stats.dom.parentNode.removeChild(stats.dom);
      }

      // 移除控制器
      if (orbitControls) {
        orbitControls.dispose();
      }

      // 移除渲染器的 DOM 元素
      if (renderer && renderer.domElement.parentNode) {
        renderer.domElement.parentNode.removeChild(renderer.domElement);
      }
    }
    renderer.dispose();
  });
</script>
